package main

import "fmt"

//指针 pointer
func main() {
	//1、&:取地址
	n := 18
	p := &n
	fmt.Println(p)
	fmt.Printf("%T\n", p)
	//2、*:根据地址取值
	fmt.Println(*p)
	fmt.Printf("%T\n", p)

	//指针与new函数
	var a *int        //定义一个名称为a的整型指针变量
	fmt.Println(a)    //打印a,显示a的值为nil(空)
	var a2 = new(int) //定义一个变量整型变量a2，并且使用new()函数为该变量申请一个内存地址(内存空间)
	fmt.Println(a2)   //打印a2,会显示a2的内存地址
	fmt.Println(*a2)  //根据a2的内存地址，去找到a2的值,打印结果为int类型的初始空值
	*a2 = 100         //给指针变量a2赋值100,会根据a2的内存地址去找到a2的值,因为值都是存储在内存空间中的
	fmt.Println(*a2)
	//make和new的区别
	//1、都是用来申请内存的，new很少用，一般用来给基本数据类型申请内存,string\int...，返回的是对应类型的指针(*string\*int)
	//2、make是用来给slice(切片)\map\chan申请内存的,make函数返回的是对应的这三个类型本身

	//	指针的指针示例
	//	1、定义一个整型变量 m
	var m int = 2
	fmt.Println("m的数值是: ", m)    //2
	fmt.Printf("%T\n", m)        //int
	fmt.Printf("m的地址是:%p\n", &m) //0xc00007e008
	//	2、定义一个指针类型的变量 prt
	var prt *int
	fmt.Printf("prt自己的地址是:%p\n", &prt) //0xc0000ce020
	fmt.Println("prt的数值是: ", prt)      //nil  因为该指针未存储任何的内存地址
	prt = &m
	fmt.Println("prt的数值是: ", prt)                   //0xc00007e008 prt的数值存储是m的内存地址,因此与m的内存地址相同
	fmt.Printf("prt自己的内存地址是:%p\n", &prt)            //0xc0000ce020
	fmt.Println("prt的数值,是m的内存地址,该地址存储的数据是: ", *prt) //2
	//	3、修改m的值 看prt是否会发生变化
	m = 3
	fmt.Printf("修改变量m后,变量m的地址是:%p\n", &m)                  //0xc00007e008  修改变量m后,m的地址并未发生改变
	fmt.Println("修改变量m后,prt的数值是: ", prt)                   //0xc00007e008 存储的还是变量m的地址
	fmt.Println("修改变量m后,prt的数值,是m的内存地址,该地址存储的数据是: ", *prt) //3
	//	4、修改指针prt的值，看是否会发生改变
	*prt = 200
	fmt.Printf("修改指针prt后,变量m的地址是:%p\n", &m)                  //0xc0000ce020
	fmt.Println(m)                                           //200
	fmt.Println("修改指针prt后,prt的数值是: ", prt)                   //0xc00007e008
	fmt.Printf("修改指针prt后,prt自己的内存地址是:%p\n", &prt)            //0xc0000ce020
	fmt.Println("修改指针prt后,prt的数值还是m的内存地址,该地址存储的数据是: ", *prt) //200
	//	5、指针的指针
	var prt1 **int                  //定义一个指针类型的指针变量
	fmt.Println("prt1的数值是: ", prt1) //nil
	prt1 = &prt
	fmt.Printf("%T,%T,%T\n", a, prt, prt1)                      //三者的类型分别是int *int **int
	fmt.Println("prt1的数值是: ", prt1)                             //prt1存储的数值是prt的内存地址 //0xc0000ce020
	fmt.Printf("prt1自身的内存地址是:%p\n", &prt1)                      //0xc00008a000
	fmt.Println("prt1中存储的地址所对应的数值就是prt的地址,对应的数据是: ", *prt1)     //0xc00007e008 这个就是m的地址
	fmt.Println("prt1中存储的地址所对应的数值就是prt的地址,在获取对应的数值是: ", **prt1) //200 对m的地址取值
}
